package org.javahispano.javacup.tacticas_aceptadas.Moyatzo.MoyatzoBraves;

import java.awt.Color;
import java.util.List;
import java.util.LinkedList;
import org.javahispano.javacup.modelo.*;

public class TacticaMoyatzoBraves implements Tactica {

	// ** Declaraciones de tipos propios de la clase. **

	// Enumerado con los posibles tipos de posesi�n.
	private enum PosesionDeBalon { RIVAL, PROPIA, DIVIDIDA };

	// Enumerado con los posibles tipos de "actitud" del equipo.
	private enum ActitudDelEquipo { ATAQUE, DEFENSA };
	
	// ** Posicionamientos de los jugadores. **
	
    Posicion adelantada_en_ataque[] = new Posicion[]{
        new Posicion( 0,													- 50	),	// Portero.
        new Posicion( 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		Constantes.RADIO_CIRCULO_CENTRAL	),	// Lateral derecho. 
        new Posicion( 0,													0		),	// Central.
        new Posicion( - 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	Constantes.RADIO_CIRCULO_CENTRAL	),	// Lateral izquierdo.
        new Posicion( 0,													( Constantes.LARGO_CAMPO_JUEGO / 2 ) - Constantes.DISTANCIA_PENAL - Constantes.RADIO_PENAL	),	// Mediapunta.
        new Posicion( ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,			Constantes.LARGO_CAMPO_JUEGO / 4	),	// Tap�n derecho.
        new Posicion( - ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		Constantes.LARGO_CAMPO_JUEGO / 4	),	// Tap�n izquierdo.
        new Posicion( 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		( Constantes.LARGO_CAMPO_JUEGO / 2 ) - Constantes.ANCHO_AREA_CHICA	), 	// Extremo derecho.
        new Posicion( - 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	( Constantes.LARGO_CAMPO_JUEGO / 2 ) - Constantes.ANCHO_AREA_CHICA	),	// Extremo izquierdo.
        new Posicion( 0.5 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	( Constantes.LARGO_CAMPO_JUEGO / 2 ) - Constantes.ANCHO_AREA_CHICA	), 	// Delantero derecho.
        new Posicion( - 0.5 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	( Constantes.LARGO_CAMPO_JUEGO / 2 ) - Constantes.ANCHO_AREA_CHICA	)   // Delantero izquierdo.
    };

    Posicion atrasada_en_ataque[] = new Posicion[]{
    	new Posicion( 0,													- 50	),	// Portero.
        new Posicion( 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL	),	// Lateral derecho. 
        new Posicion( 0, 													- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL	),	// Central.
        new Posicion( - 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL	),	// Lateral izquierdo.
        new Posicion( 0,													- ConstantesMoyatzoBraves.LINEA_TRES_CUARTOS	),	// Mediapunta.
        new Posicion( ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,			- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL + Constantes.RADIO_PENAL	),	// Tap�n derecho.
        new Posicion( - ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL + Constantes.RADIO_PENAL	),	// Tap�n izquierdo.
        new Posicion( 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		- ConstantesMoyatzoBraves.LINEA_TRES_CUARTOS	), 	// Extremo derecho.
        new Posicion( - 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	- ConstantesMoyatzoBraves.LINEA_TRES_CUARTOS	),	// Extremo izquierdo.
        new Posicion( ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,			- Constantes.RADIO_CIRCULO_CENTRAL	),	// Delantero derecho.
        new Posicion( - ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		0	) 	// Delantero izquierdo.
    };

    Posicion adelantada_en_defensa[] = new Posicion[]{
    	new Posicion( 0,													- 50	),	// Portero.
        new Posicion( 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		0	),	// Lateral derecho.
        new Posicion( 0,													0	),	// Central.
        new Posicion( - 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	0	),	// Lateral izquierdo.
        new Posicion( 0,													ConstantesMoyatzoBraves.LINEA_TRES_CUARTOS	),	// Mediapunta.
        new Posicion( ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,			Constantes.RADIO_CIRCULO_CENTRAL	),	// Tap�n derecho.
        new Posicion( - ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		Constantes.RADIO_CIRCULO_CENTRAL	),	// Tap�n izquierdo.
        new Posicion( 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		ConstantesMoyatzoBraves.LINEA_TRES_CUARTOS	), 	// Extremo derecho.
        new Posicion( - 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	ConstantesMoyatzoBraves.LINEA_TRES_CUARTOS	),	// Extremo izquierdo.
        new Posicion( ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,			( Constantes.LARGO_CAMPO_JUEGO / 2 ) - Constantes.DISTANCIA_PENAL - Constantes.RADIO_PENAL	), 	// Delantero derecho.
        new Posicion( ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,			( Constantes.LARGO_CAMPO_JUEGO / 2 ) - Constantes.DISTANCIA_PENAL - Constantes.RADIO_PENAL	) 	// Delantero izquierdo.
    };

    Posicion atrasada_en_defensa[] = new Posicion[]{
        new Posicion( 0,													- 50	),	// Portero.
    	new Posicion( 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.ANCHO_AREA_CHICA	),	// Lateral derecho. 
    	new Posicion( 0,													- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.ANCHO_AREA_CHICA	),	// Central.
    	new Posicion( - 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.ANCHO_AREA_CHICA	),	// Lateral izquierdo.
    	new Posicion( 0, 	- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL + Constantes.RADIO_PENAL	),	// Mediapunta.
    	new Posicion( ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,			- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL	),	// Tap�n derecho.
    	new Posicion( - ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL	),	// Tap�n izquierdo.
    	new Posicion( 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		- ConstantesMoyatzoBraves.LINEA_TRES_CUARTOS 	),	// Extremo derecho.
    	new Posicion( - 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	- ConstantesMoyatzoBraves.LINEA_TRES_CUARTOS	),	// Extremo izquierdo.
    	new Posicion( 0.5 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	- Constantes.LARGO_CAMPO_JUEGO / 6	),	// Delantero derecho.
    	new Posicion( - ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		- Constantes.RADIO_CIRCULO_CENTRAL	)	// Delantero izquierdo.
    };

    Posicion sacamos[] = new Posicion[]{
    	new Posicion( 0,													- 50	),	// Portero.
        new Posicion( 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL + Constantes.RADIO_PENAL	),	// Lateral derecho. 
        new Posicion( 0, 													- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL + Constantes.RADIO_PENAL	),	// Central.
        new Posicion( - 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL + Constantes.RADIO_PENAL	),	// Lateral izquierdo.
        new Posicion( 0,													- Constantes.RADIO_CIRCULO_CENTRAL - Constantes.DISTANCIA_CONTROL_BALON	),	// Mediapunta.
        new Posicion( ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,			- Constantes.LARGO_CAMPO_JUEGO / 6	),	// Tap�n derecho.
        new Posicion( - ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		- Constantes.LARGO_CAMPO_JUEGO / 6	),	// Tap�n izquierdo.
        new Posicion( 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		- Constantes.DISTANCIA_CONTROL_BALON	), 	// Extremo derecho.
        new Posicion( - 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	- Constantes.DISTANCIA_CONTROL_BALON	),	// Extremo izquierdo.
        new Posicion( 0, 													0										),	// Delantero derecho.
        new Posicion( - Constantes.DISTANCIA_CONTROL_BALON,					- Constantes.DISTANCIA_CONTROL_BALON	) 	// Delantero izquierdo.
    };

    Posicion sacan[] = new Posicion[]{
    	new Posicion( 0,													- 50	),	// Portero.
        new Posicion( 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL + Constantes.RADIO_PENAL	),	// Lateral derecho. 
        new Posicion( 0, 													- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL + Constantes.RADIO_PENAL	),	// Central.
        new Posicion( - 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	- ( Constantes.LARGO_CAMPO_JUEGO / 2 ) + Constantes.DISTANCIA_PENAL + Constantes.RADIO_PENAL	),	// Lateral izquierdo.
        new Posicion( 0,													- Constantes.RADIO_CIRCULO_CENTRAL - Constantes.DISTANCIA_CONTROL_BALON	),	// Mediapunta.
        new Posicion( ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,			- Constantes.LARGO_CAMPO_JUEGO / 6	),	// Tap�n derecho.
        new Posicion( - ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		- Constantes.LARGO_CAMPO_JUEGO / 6	),	// Tap�n izquierdo.
        new Posicion( 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,		- Constantes.DISTANCIA_CONTROL_BALON	), 	// Extremo derecho.
        new Posicion( - 2 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	- Constantes.DISTANCIA_CONTROL_BALON	),	// Extremo izquierdo.
        new Posicion( Constantes.RADIO_CIRCULO_CENTRAL + Constantes.DISTANCIA_CONTROL_BALON, 	- Constantes.DISTANCIA_CONTROL_BALON	),	// Delantero derecho.
        new Posicion( - Constantes.RADIO_CIRCULO_CENTRAL - Constantes.DISTANCIA_CONTROL_BALON,	- Constantes.DISTANCIA_CONTROL_BALON	) 	// Delantero izquierdo.
    };
    
    double bascular_a_derecha[] = new double[]{
    	0, // Portero.
    	0.75 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS,	// Lateral derecho.
    	0.9  * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Central.
    	0.5  * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Lateral izquierdo.
    	0.9  * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Mediapunta.
    	1 	 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Tap�n derecho.
    	0.7  * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Tap�n izquierdo.
    	0.75 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Extremo derecho.
    	0.5  * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Extremo izquierdo.
    	1    * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Delantero derecho.
    	0.7  * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Delantero izquierdo.
    };

    double bascular_a_izquierda[] = new double[]{
    	0, // Portero.
        - 0.5  * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Lateral derecho.
        - 0.9  * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Central.
        - 0.75 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Lateral izquierdo.
        - 0.9  * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Mediapunta.
        - 0.7  * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Tap�n derecho.
        - 1    * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Tap�n izquierdo.
        - 0.5  * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Extremo derecho.
        - 0.75 * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Extremo izquierdo.
        - 0.7  * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Delantero derecho.
        - 1    * ConstantesMoyatzoBraves.DIST_LAT_ENTRE_JUGS, // Delantero izquierdo.
        };
    
    private Posicion[] _posiciones_teoricas = new Posicion[10];
    
    private int _i_jug_destino_pase = -1;
    
    // Guarda la posici�n del bal�n en la iteraci�n anterior.
    private Posicion _pos_balon_it_anterior = new Posicion();

    class TacticaDetalleImpl implements TacticaDetalle {

        public String getNombre() {
            return "Moyatzo Braves";
        }

        public String getPais() {
            return "España";
        }

        public String getEntrenador() {
            return "Moyatzo";
        }

        public Color getColorCamiseta() {
            return new Color(0, 0, 200);
        }

        public Color getColorPantalon() {
            return new Color(0, 0, 200);
        }

        public Color getColorFranja() {
            return new Color(170, 0, 0);
        }

        public Color getColorCalcetas() {
            return new Color(0, 0, 200);
        }

        public Color getColorPortero() {
            return new Color(0, 255, 50);
        }

        public EstiloUniforme getEstilo() {
            return EstiloUniforme.LINEAS_VERTICALES;
        }

        public Color getColorCamiseta2() {
            return new Color(255, 255, 0);
        }

        public Color getColorPantalon2() {
            return new Color(0, 0, 200);
        }

        public Color getColorFranja2() {
            return new Color(0, 0, 200);
        }

        public Color getColorCalcetas2() {
            return new Color(255, 255, 0);
        }

        public Color getColorPortero2() {
            return new Color(0, 255, 50);
        }

        public EstiloUniforme getEstilo2() {
            return EstiloUniforme.FRANJA_DIAGONAL;
        }

        class JugadorImpl implements JugadorDetalle {

            String nombre;
            int numero;
            Color piel, pelo;
            double velocidad, remate, presicion;
            boolean portero;
            Posicion posicion;

            public JugadorImpl(String nombre, int numero, Color piel, Color pelo,
                    double velocidad, double remate, double presicion, boolean portero) {
                this.nombre=nombre;
                this.numero=numero;
                this.piel=piel;
                this.pelo=pelo;
                this.velocidad=velocidad;
                this.remate=remate;
                this.presicion=presicion;
                this.portero=portero;
            }

            public String getNombre() {
                return nombre;
            }

            public Color getColorPiel() {
                return piel;
            }

            public Color getColorPelo() {
                return pelo;
            }

            public int getNumero() {
                return numero;
            }

            public boolean esPortero() {
                return portero;
            }

            public double getVelocidad() {
                return velocidad;
            }

            public double getRemate() {
                return remate;
            }

            public double getPresicion() {
                return presicion;
            }

        }

        public JugadorDetalle[] getJugadores() {
            return new JugadorDetalle[]{
                    new JugadorImpl("Jordi Barrado", 1, new Color(204,153,0), new Color(50,0,0),1.0d,1.0d,0.0d, true),
                    new JugadorImpl("Alvaro Teixido", 2, new Color(255,200,150), new Color(50,0,0),1.0d,0.5d,1.0d, false),
                    new JugadorImpl("Sergio Daniel Diaz Casas", 4, new Color(255,200,150), new Color(153,153,0),1.0d,0.5d,1.0d, false),
                    new JugadorImpl("Xil Couzo", 3, new Color(153,102,0), new Color(50,0,0),1.0d,0.5d,1.0d, false),
                    new JugadorImpl("Toni Mir", 8, new Color(255,200,150), new Color(102,102,0),1.0d,1.0d,1.0d, false),
                    new JugadorImpl("Pietro Rispoli", 6, new Color(255,200,150), new Color(50,0,0),1.0d,0.5d,1.0d, false),
                    new JugadorImpl("Eduardo Arteiro", 5, new Color(153,102,0), new Color(50,0,0),1.0d,0.5d,1.0d, false),
                    new JugadorImpl("Scott Court", 7, new Color(255,200,150), new Color(102,51,0),1.0d,0.5d,0.5d, false),
                    new JugadorImpl("Seth Brandsteder", 11, new Color(255,200,150), new Color(50,0,0),1.0d,0.5d,0.5d, false),
                    new JugadorImpl("Francisco Pajares", 9, new Color(255,200,150), new Color(102,51,0),1.0d,1.0d,1.0d, false),
                    new JugadorImpl("Anton Lauzurica", 10, new Color(255,200,150), new Color(153,153,0),1.0d,1.0d,1.0d, false)
                    };
        }
    }

    TacticaDetalle detalle=new TacticaDetalleImpl();
    public TacticaDetalle getDetalle() {
        return detalle;
    }

    public Posicion[] getPosicionSaca(SituacionPartido sp) {
    return sacamos;
    }

    public Posicion[] getPosicionRecive(SituacionPartido sp) {
    return sacan;
    }
    
    //-----
    
    // ** Variables propias de la clase ** 
    
    // Lista de comandos a ejecutar.
    private LinkedList<Comando> _lista_de_comandos = new LinkedList<Comando>();
    
    // Recordamos la posesi�n del bal�n en la anterior iteraci�n
    //  (inicializamos con RIVAL por precauci�n).
    private PosesionDeBalon _posesion_anterior = PosesionDeBalon.RIVAL;
    
    // Variable que guarda la situaci�n del partido actual (para no transmitirla
    //  como par�metro a los m�todos auxiliares).
    private SituacionPartido _situacion_partido_actual;
    
    //-----
    
    // M�todo que permite averiguar qui�n tiene la posesi�n (qui�n
    //  puede chutar el bal�n o qui�n lo hizo en �ltimo lugar).
    private PosesionDeBalon DeterminaPosesionDeBalon( )
    {
    	// Guardamos el (antiguo) �ndice que marca el jugador "destino"
    	//  de un pase o auto-pase.
    	int i_jug_dest = _i_jug_destino_pase;
    	
    	// Borramos el �ndice.
    	_i_jug_destino_pase = -1;
    	
    	// Si debe sacar el rival, defenderemos.
    	if ( _situacion_partido_actual.sacaRival())
    		return PosesionDeBalon.RIVAL;
    	
    	// Si sacamos nosotros, podemos atacar.
    	if ( _situacion_partido_actual.saco())
    		return PosesionDeBalon.PROPIA;

    	// Averiguamos si nosotros podemos o ellos pueden golpear el bal�n.
    	boolean b_pueden_rematar = PuedenRematar( ),
    		b_podemos_rematar = PodemosRematar( );
    	
    	// Si alg�n rival puede rematar...
    	if ( b_pueden_rematar )
    	{
    		// �Podemos nosotros?
    		if ( b_podemos_rematar )
    			return PosesionDeBalon.DIVIDIDA;
    		else
    			return PosesionDeBalon.RIVAL;
    	}
    	// Si pudi�ramos nosotros, entonces la posesi�n es nuestra.
    	else if ( b_podemos_rematar )
    		return PosesionDeBalon.PROPIA;

    	// Si hemos llegado hasta aqu�, restauramos el antiguo valor
    	//  del �ndice que marca el receptor de un pase o auto-pase.
    	_i_jug_destino_pase = i_jug_dest;
    	
    	// Por defecto, suponemos que la posesi�n no ha cambiado.
    	return _posesion_anterior;
    }
    
    //-----
    
    // Determina si alg�n jugador rival est� en disposici�n de golpear el bal�n.
    private boolean PuedenRematar( )
    {
    	// Consultamos los rivales que est�n en disposici�n de golpear el bal�n.
    	int rivales_pueden_rematar[] = _situacion_partido_actual.puedenRematarRival();
    	int num_rivales_pueden_rematar = rivales_pueden_rematar.length;
    	
    	// Si alg�n jugador rival puede rematar se retorna 'true'.
    	return ( num_rivales_pueden_rematar > 0 );
    }
    
    //-----
    
    // Determina si alg�n jugador propio est� en disposici�n de golpear el bal�n.
    private boolean PodemosRematar( )
    {
    	// Consultamos los jugadores propios que est�n en disposici�n
    	//  de golpear el bal�n.
    	int propios_pueden_rematar[] = _situacion_partido_actual.puedenRematar();
    	int num_propios_pueden_rematar = propios_pueden_rematar.length;
    	
    	// Si alg�n jugador propio puede rematar se retorna 'true'.
    	return ( num_propios_pueden_rematar > 0 );
    }
    
    //-----
    
    // Da las instrucciones al equipo en caso de tener la posesi�n
    //  del bal�n (atacando). 
    private void InstruccionesEnAtaque( )
    {
    	// Reposiciona los jugadores en funci�n de donde est� el bal�n.
    	ReposicionaJugadoresDeCampo( ActitudDelEquipo.ATAQUE );
    	
    	// Reposicionamos al portero.
    	ReposicionaPortero( );
    	
    	// Instrucciones para acercar al jugador m�s adecuado al bal�n.
    	AproximaJugadorAlBalon( );

    	// Instrucciones de golpeo de bal�n.
    	InstruccionesGolpeoBalon( );
    }

    //-----

	// Instrucciones para acercar al jugador m�s adecuado al bal�n.
	private void AproximaJugadorAlBalon( )
	{
		// Obtenemos la posici�n del bal�n.
		Posicion pos_balon = _situacion_partido_actual.balon();
		
		// Si es un saque de puerta...
		if ( Utilidades.EsSaqueDePuerta(_situacion_partido_actual))
		{
			// A�adimos la instrucci�n que aproxima el portero al bal�n.
			_lista_de_comandos.add(new ComandoIrA(0, pos_balon));
		}
		// Si es otro tipo de saque, aproximamos al jugador que "te�ricamente"
		//  deber�a estar m�s cerca.
		else if ( _situacion_partido_actual.saco() )
		{
			// Obtenemos el �ndice del jugador propio m�s cercano (posiciones
			//  te�ricas).
			int i_indice_jug = pos_balon.indiceMasCercano(_posiciones_teoricas);
				
			// Sumamos "1" porque el portero no estaba dentro del "array" de
			//  posiciones te�ricas.
			i_indice_jug++;
				
			// A�adimos la instrucci�n a la lista de comandos.
			_lista_de_comandos.add(new ComandoIrA(i_indice_jug, pos_balon));
		}
		else
		{
			// En pases o auto-pases tenemos guardado el �ndice del jugador
			//  que debe recibir ese pase o auto-pase. �Que se acerque al bal�n!
			if ( _i_jug_destino_pase > 0 )
			{
				// A�adimos la instrucci�n a la lista de comandos.
				_lista_de_comandos.add(new ComandoIrA(_i_jug_destino_pase, pos_balon));
			}
			
			// Obtenemos la posici�n actual de mis jugadores.
			Posicion pos_jugs[] = _situacion_partido_actual.misJugadores();
			
			// Obtenemos los �ndices de los jugadores propios ordenados
			//  por cercan�a al bal�n (posici�n real).
			int i_indices_jugs[] = pos_balon.indicesMasCercanos(pos_jugs);
			
			// Iteraciones que le quedan a cada jugador para poder rematar.
			int its_para_remat[] = _situacion_partido_actual.iteracionesParaRematar();
			
			boolean b_fin = false;
			int i_index = 0, i_jug_actual = 0, i_num_jugs = i_indices_jugs.length,
				i_jug_elegido = i_indices_jugs[0];
			
			// Buscamos el jugador m�s cercano que puede rematar.
			while ( !b_fin )
			{
				// Obtenemos el jugador "actual".
				i_jug_actual = i_indices_jugs[i_index];
				
				// �Puede rematar?
				if ( its_para_remat[i_jug_actual] == 0 )
				{
					// �Encontrado! Este jugador es el que se acercar�.
					i_jug_elegido = i_jug_actual;
					b_fin = true;
				}
				else
				{
					i_index++;
					b_fin = ( i_index > ( i_num_jugs - 1 ) );
				}
			}
			
			// Predecimos la posici�n donde estar� el bal�n en la pr�xima iteraci�n
			//  (podemos hacerlo porque antes ya hemos determinado que el rival no
			//   puede golpear el bal�n y que la posesi�n es nuestra). 
			Posicion pos_balon_futura =
				Utilidades.PredicePosBalon(_pos_balon_it_anterior, pos_balon, _situacion_partido_actual.alturaBalon());

			// Si estamos m�s cerca del posici�n del bal�n en el futuro, como ning�n
			//  rival va a golpearla y, por tanto, no va a cambiar de trayectoria,
			//  nos movemos a la posici�n futura.
			if ( Utilidades.DistanciaAlCuadrado( pos_jugs[i_jug_elegido], pos_balon_futura ) <
				 Utilidades.DistanciaAlCuadrado( pos_jugs[i_jug_elegido], pos_balon ) )
				_lista_de_comandos.add(new ComandoIrA(i_jug_elegido, pos_balon_futura));
			else
				_lista_de_comandos.add(new ComandoIrA(i_jug_elegido, pos_balon));
			
			// Si no estamos haciendo un pase o un auto-pase, y tampoco podemos
			//  golpear el bal�n en esta iteraci�n...
			if ( ( _i_jug_destino_pase < 0 ) && ( !PodemosRematar( ) ) )
			{
				// Obtenemos los �ndices de los jugadores propios ordenados
				//  por cercan�a al bal�n (posici�n real), exceptuando al portero
				//  y al jugador que ya se aproxima al bal�n por los c�lculos
				//  anteriores.
				int i_nuevos_indices[] = pos_balon.indicesMasCercanos(pos_jugs, 0, i_jug_elegido);

				// N�mero de intentos que realizaremos (normalmente, la constante).
				int i_num_intentos = Math.min( ConstantesMoyatzoBraves.NUM_JUGS_SE_APROXIMA_BALON, i_nuevos_indices.length);
				
				double d_dist1, d_dist2;
				
				for ( i_index = 0; ( i_index < i_num_intentos ); i_index++ )
				{
					// Obtenemos el jugador actual.
					i_jug_actual = i_nuevos_indices[i_index];
					
					// Obtenemos las distancias respecto a las posiciones actual y futura del bal�n.
					d_dist1 = Utilidades.DistanciaAlCuadrado(pos_jugs[i_jug_actual], pos_balon);
					d_dist2 = Utilidades.DistanciaAlCuadrado(pos_jugs[i_jug_actual], pos_balon_futura);

					if ( d_dist2 < d_dist1 )
					{
						// El bal�n se acerca al jugador. �Que el jugador se acerque al bal�n!
						_lista_de_comandos.add(new ComandoIrA(i_jug_actual, pos_balon_futura));
						
						// S�lo lo haremos con uno de los jugadores posibles.
						i_index = i_num_intentos;
					}
				}
			}
		}
	}

    //-----
    
	// Determina las instrucciones de golpeo de bal�n (decide si pasar, chutar,
    //  etc.) y lo ejecuta.
    private void InstruccionesGolpeoBalon()
    {
    	// Almacena el "mejor golpeo posible" en esta situaci�n.
    	InstruccionGolpeoBalon gb = new InstruccionGolpeoBalon();
    	
    	// Opta por despejar el bal�n.
    	EjecutaDespeje( gb, false );
    	
    	// Intenta el disparo a puerta.
    	if ( gb.getAccionConBalon() == InstruccionGolpeoBalon.AccionConBalon.NINGUNA )
    		EjecutaDisparo( gb );
    	
    	// Intenta el pase en corto.
    	if ( gb.getAccionConBalon() == InstruccionGolpeoBalon.AccionConBalon.NINGUNA )
    		EjecutaPase( gb );
    	
    	// Intenta avanzar con el bal�n.
    	if ( gb.getAccionConBalon() == InstruccionGolpeoBalon.AccionConBalon.NINGUNA ||
    		 gb.getAccionConBalon() == InstruccionGolpeoBalon.AccionConBalon.PASE )
    		EjecutaAvanceConBalon( gb );
    	
    	// Si hemos llegado hasta aqu�, hay que despejar s� o s�.
    	if ( gb.getAccionConBalon() == InstruccionGolpeoBalon.AccionConBalon.NINGUNA )
    		EjecutaDespeje( gb, true );
    	
    	// ** Una vez elegida la mejor opci�n, la ejecutamos. **
    	
   		// Jugadores propios que pueden rematar.
   		int[] i_jugs_pueden_rematar = _situacion_partido_actual.puedenRematar();
   		int i_num_jugs_pueden_rematar = i_jugs_pueden_rematar.length, i_jug_actual; 
    		
   		// Para todo jugador que pueda rematar...
   		for ( int i_index = 0; ( i_index < i_num_jugs_pueden_rematar ); i_index++ )
   		{
   			// Toma el jugador "actual".
   			i_jug_actual = i_jugs_pueden_rematar[i_index];

   			// Si la mejor opci�n es un pase...
   			if ( gb.getAccionConBalon() == InstruccionGolpeoBalon.AccionConBalon.PASE )
   			{
   				// Obtenemos la posici�n de destino del bal�n.
   				Posicion pos_destino = gb.getPosicionDestino();
   				
   				// A�ade el "comando de pase" (tercer par�metro: fuerza; cuarto: si es alto o no).
   				_lista_de_comandos.add(
   						new ComandoGolpearBalon(i_jug_actual, pos_destino, 1, false));
   				
   				// Obtenemos la posici�n de mis jugadores.
   				Posicion pos_mis_jugs[] = _situacion_partido_actual.misJugadores();
   				
   				// Guardamos el �ndice del jugador "destino" del pase / auto-pase.
   				_i_jug_destino_pase =  pos_destino.indiceMasCercano(pos_mis_jugs);
   			}
   			// Si la mejor opci�n es disparar...
   			else if ( gb.getAccionConBalon() == InstruccionGolpeoBalon.AccionConBalon.DISPARO )
   			{
   				// Obtenemos la posici�n de mis jugadores.
   				Posicion pos_mis_jugs[] = _situacion_partido_actual.misJugadores();
   				
   				// Obtenemos la posici�n del bal�n.
   				Posicion pos_balon = _situacion_partido_actual.balon();
   				
   				// Obtenemos el �ndice del jugador m�s cercano al bal�n (exceptuando
   				//  al portero).
   				int i_jug_mas_cercano = pos_balon.indiceMasCercano(pos_mis_jugs, 0);
   				
   				// Obtenemos el �ngulo vertical.
   				double d_ang_vert = gb.getAnguloVertical();
   				
   				// Si el jugador actual no es el m�s cercano, que dispare raso.
   				//  Los c�lculos utilizan informaci�n del m�s cercano.
   				if ( i_jug_actual != i_jug_mas_cercano )
   					d_ang_vert = 0.0;
   				
   				// A�ade el "comando de disparo" (tercer par�metro: fuerza; cuarto: �ngulo vertical).
   				_lista_de_comandos.add(
   						new ComandoGolpearBalon(i_jug_actual, gb.getPosicionDestino(), 1, d_ang_vert));
   			}
   			else if ( gb.getAccionConBalon() == InstruccionGolpeoBalon.AccionConBalon.AVANZAR_CON_BALON )
   			{
   				// Obtenemos la posici�n de mis jugadores.
   				Posicion pos_mis_jugs[] = _situacion_partido_actual.misJugadores();
   				
   				// Obtenemos la posici�n del jugador que se va a hacer el auto-pase.
   				Posicion pos_jug = pos_mis_jugs[i_jug_actual];
   				
   				// Calculamos la posicion de destino del jugador.
   				Posicion pos_dest = pos_jug.moverAngulo(gb.getAnguloAvanceConBalon(), Constantes.VELOCIDAD_MAX);
   				
   				// A�ade el "comando de avanzar con bal�n".
   				_lista_de_comandos.add(new ComandoIrA(i_jug_actual, pos_dest));
   				_lista_de_comandos.add(new ComandoGolpearBalon(i_jug_actual));
   				
   				// Es un auto-pase, el que la chuta la persigue.
   				_i_jug_destino_pase = i_jug_actual;
   				
   				// S�lo queremos avanzar con un jugador, finalizamos el bucle.
   				i_index = i_num_jugs_pueden_rematar;
   			}
   			// Si la mejor opci�n es despejar...
   			else if ( gb.getAccionConBalon() == InstruccionGolpeoBalon.AccionConBalon.DESPEJE )
   			{
   				// A�ade el "comando de despeje" (tercer par�metro: fuerza; cuarto: �ngulo vertical).
   				_lista_de_comandos.add(
   						new ComandoGolpearBalon(i_jug_actual, gb.getPosicionDestino(), gb.getFuerza(), gb.getAnguloVertical()));
   			}
   		}
    }
    
    //-----
    
	// Intenta el disparo a puerta.
	private void EjecutaDisparo( InstruccionGolpeoBalon a_golpeo_balon )
	{
		// Obtenemos la posici�n actual del bal�n.
		Posicion pos_balon = _situacion_partido_actual.balon();
		
		// Obtenemos el �ngulo respecto al arco.
		double d_ang_balon_arco =
			pos_balon.angulo(Constantes.centroArcoSup);
		
		// Lo pasamos a grados.
		d_ang_balon_arco = d_ang_balon_arco * ( 180.0 / Math.PI ); 
		d_ang_balon_arco = Math.abs( d_ang_balon_arco - 90.0 ); 
		
		// Calcula la distancia del bal�n al arco rival.
		double d_dist = pos_balon.distancia(Constantes.centroArcoSup);
		
		// Calcula la distancia m�xima ideal en funci�n del �ngulo de remate
		//  que tengamos seg�n la posici�n en la que estamos (�toma ya!).
		double d_dist_max_disp_segun_angulo =
			ConstantesMoyatzoBraves.MIN_DIST_DISPARO + ( ( 1 - ( d_ang_balon_arco / 90.0 ) ) * ConstantesMoyatzoBraves.DIF_DISTS_DISPARO ); 
		
		// Si estamos m�s lejos de lo "ideal", no se chuta.
		if ( d_dist > d_dist_max_disp_segun_angulo )
			return;
		
		// Obtenemos el �ndice del jugador rival que hace de portero.
		int i_ind_port_rival =
			Utilidades.ObtenerIndicePorteroRival(_situacion_partido_actual);
		
		// No hemos encontrado al portero, chutamos al medio.
		if ( i_ind_port_rival == -1 )
			a_golpeo_balon.ChutarBalon( Constantes.centroArcoSup, 0.0 );
		else
		{
			// Obtenemos las posiciones de todos los rivales.
			Posicion pos_rivales[] = _situacion_partido_actual.rivales();
			
			// Obtenemos la posici�n del portero rival.
			Posicion pos_portero_rival = pos_rivales[i_ind_port_rival];
			
			// Calculamos los �ngulos que forma el bal�n con los 2 postes
			//  y con el portero rival.
			double d_ang_poste_izq = pos_balon.angulo(Constantes.posteIzqArcoSup),
				d_ang_poste_der = pos_balon.angulo(Constantes.posteDerArcoSup),
				d_ang_portero_rival = pos_balon.angulo(pos_portero_rival);
			
			if ( Math.abs( d_ang_poste_izq - d_ang_portero_rival ) >
				 Math.abs( d_ang_poste_der - d_ang_portero_rival ) )
			{
				// Tiramos a la izquierda del arco.
				
				// Obtenemos la distancia al poste izquierdo.
				double d_dist_poste = pos_balon.distancia(Constantes.posteIzqArcoSup);
				
				// Obtenemos el error de disparo del jugador que va a rematar
				//  (si dos o m�s jugadores pueden rematar, puede que haya un error
				//  si el que dispara finalmente no es el m�s cercano al bal�n).
				
				// Posici�n de mis jugadores.
				Posicion pos_jugs[] = _situacion_partido_actual.misJugadores();
				
				// Obtenemos el �ndice del m�s cercano.
				int i_jug_mas_cercano = pos_balon.indiceMasCercano(pos_jugs);
				
				// Obtenemos los detalles de mis jugadores.
				JugadorDetalle[] detalles_jugs = _situacion_partido_actual.detalleMisJugadores();
				
				// Obtenemos el error del jugador m�s cercano.
				double d_factor_error = detalles_jugs[i_jug_mas_cercano].getPresicion(),
					d_error_ang = Constantes.ERROR_MAX - ( d_factor_error * ConstantesMoyatzoBraves.DIF_ERROR_MAX_MIN );

				// Correcci�n a aplicar al �ngulo de disparo.
				double d_correccion_angular = ( d_error_ang / 2 ) * Math.PI;
				
				// �ngulo REAL con el que se realizar� el disparo.
				double d_angulo_disparo = ( d_ang_poste_izq - d_correccion_angular );
				
				// Calculamos la posici�n "destino" del golpeo de bal�n.
				Posicion pos_destino_chute =
					pos_balon.moverAngulo(d_angulo_disparo, d_dist_poste);

				// Calculamos el �ngulo vertical utilizado en el golpeo.
				double d_ang_vert =
					Utilidades.DeterminaAnguloVerticalDisparo(d_angulo_disparo, _situacion_partido_actual);
				
				// Instrucci�n de golpeo.
				a_golpeo_balon.ChutarBalon( pos_destino_chute, d_ang_vert );
			}
			else
			{
				// Tiramos a la derecha del arco.

				// Obtenemos la distancia al poste derecho.
				double d_dist_poste = pos_balon.distancia(Constantes.posteDerArcoSup);

				// Obtenemos el error de disparo del jugador que va a rematar
				//  (si dos o m�s jugadores pueden rematar, puede que haya un error
				//  si el que dispara finalmente no es el m�s cercano al bal�n).
				// Posici�n de mis jugadores.
				Posicion pos_jugs[] = _situacion_partido_actual.misJugadores();
				
				// Obtenemos el �ndice del m�s cercano.
				int i_jug_mas_cercano = pos_balon.indiceMasCercano(pos_jugs);
				
				// Obtenemos los detalles de mis jugadores.
				JugadorDetalle[] detalles_jugs = _situacion_partido_actual.detalleMisJugadores();
				
				// Obtenemos el error del jugador m�s cercano.
				double d_factor_error = detalles_jugs[i_jug_mas_cercano].getPresicion(),
					d_error_ang = Constantes.ERROR_MAX - ( d_factor_error * ConstantesMoyatzoBraves.DIF_ERROR_MAX_MIN );
				
				// Correcci�n a aplicar al �ngulo de disparo.
				double d_correccion_angular = ( d_error_ang / 2 ) * Math.PI;
				
				// �ngulo REAL con el que se realizar� el disparo.
				double d_angulo_disparo = ( d_ang_poste_der + d_correccion_angular );
				
				// Calculamos la posici�n "destino" del golpeo de bal�n.
				Posicion pos_destino_chute =
					pos_balon.moverAngulo(d_angulo_disparo, d_dist_poste);

				// Calculamos el �ngulo vertical utilizado en el golpeo.
				double d_ang_vert =
					Utilidades.DeterminaAnguloVerticalDisparo(d_angulo_disparo, _situacion_partido_actual);
				
				// Instrucci�n de golpeo.
				a_golpeo_balon.ChutarBalon( pos_destino_chute, d_ang_vert );
			}
		}
	}

	//-----
	
	// Intenta el pase en corto.
	private void EjecutaPase( InstruccionGolpeoBalon a_golpeo_balon )
	{
		// Obtenemos la posici�n del bal�n.
		Posicion pos_balon = _situacion_partido_actual.balon();

		// Posici�n actual de mis jugadores.
		Posicion[] pos_mis_jugs = _situacion_partido_actual.misJugadores();
		
		// Posici�n actual de los rivales.
		Posicion[] pos_rivales = _situacion_partido_actual.rivales();
		
		// Detalles de mis jugadores.
		JugadorDetalle[] jug_det_mis_jugs = _situacion_partido_actual.detalleMisJugadores();
		
		// Obtenemos la lista de jugadores ordenados por proximidad al bal�n.
		int i_indices_jugs[] = pos_balon.indicesMasCercanos(pos_mis_jugs);
		
		// Iteraciones que le quedan a cada jugador para poder rematar.
		int its_para_remat[] = _situacion_partido_actual.iteracionesParaRematar();
		
		int i_jug_actual, i_rival_mas_cercano;
		Posicion pos_jug_actual, pos_pto_medio_pase;
		double d_dist_al_cuad, d_dist_receptor_al_cuad, d_dist_rival_al_cuad;
		
		// Intentamos hacer el pase.
		for ( int i_index = 0; i_index < ConstantesMoyatzoBraves.NUM_INTENTOS_PASE; i_index++ )
		{
			// Obtenemos el jugador "actual".
			i_jug_actual = i_indices_jugs[i_index];
			
			// Al portero no se la pasamos, hay riesgo de marcar en propia.
			if ( jug_det_mis_jugs[i_jug_actual].esPortero() )
				continue;
			
			// �Podr�a golpear el bal�n si se lo damos? Si no, lo descartamos.
			if ( its_para_remat[i_jug_actual] > 0 )
				continue;
			
			// Posici�n del jugador.
			pos_jug_actual = pos_mis_jugs[i_jug_actual];
			
			// Distancia (al cuadrado) respecto al bal�n.
			d_dist_al_cuad =
				Utilidades.DistanciaAlCuadrado(pos_jug_actual, pos_balon);
			
			// Si est� demasiado cerca tampoco es buen candidato.
			if ( d_dist_al_cuad < ConstantesMoyatzoBraves.MIN_DIST_PASE_AL_CUADRADO )
				continue;
			
			// Obtenemos el punto medio entre el bal�n y el jugador candidato a
			//  recibir el pase.
			pos_pto_medio_pase = Posicion.media(pos_balon, pos_jug_actual);
		
			// Obtenemos el �ndice del jugador rival m�s cercano al punto
			//  medio del pase.
			i_rival_mas_cercano = pos_pto_medio_pase.indiceMasCercano(pos_rivales);
			
			// C�lculo de las distancias del receptor y del rival m�s cercano al
			//  punto medio del pase.
			d_dist_receptor_al_cuad =
				Utilidades.DistanciaAlCuadrado(pos_pto_medio_pase, pos_jug_actual);
			d_dist_rival_al_cuad =
				Utilidades.DistanciaAlCuadrado(pos_pto_medio_pase, pos_rivales[i_rival_mas_cercano]);
			
			// Si est� m�s cerca el rival, tampoco hacemos el pase.
			if ( d_dist_rival_al_cuad < d_dist_receptor_al_cuad )
				continue;
			
			// Almacenamos la informaci�n del pase encontrado.
			a_golpeo_balon.PasarBalon(pos_jug_actual);
		}
	}

    //-----
	
	// Intenta avanzar con el bal�n.
	private void EjecutaAvanceConBalon( InstruccionGolpeoBalon a_golpeo_balon )
	{
		// Obtenemos la posici�n del bal�n.
		Posicion pos_balon = _situacion_partido_actual.balon();
		
		// Tratamiento previo. Si podemos hacer un pase, y �ste adelanta el bal�n,
		//  mejor lo hacemos y nos olvidamos de avanzar con el bal�n.
		if ( a_golpeo_balon.getAccionConBalon() == InstruccionGolpeoBalon.AccionConBalon.PASE )
		{
			// Obtenemos la posici�n de destino del pase.
			Posicion pos_dest_pase = a_golpeo_balon.getPosicionDestino();
			
			// Calculamos la distancia (al cuadrado) entre el destino del pase y
			//  la porter�a rival.
			double d_dist_pase_arco = Utilidades.DistanciaAlCuadrado(pos_dest_pase, Constantes.centroArcoSup);
			
			// Calculamos la distancia de la posici�n actual del bal�n al arco contrario.
			double d_dist_balon_arco = Utilidades.DistanciaAlCuadrado(pos_balon, Constantes.centroArcoSup);
			
			// Si el pase va a adelantar el bal�n, lo realizamos sin dudar.
			if ( d_dist_pase_arco < d_dist_balon_arco )
				return;
		}
		
		// Si estamos m�s all� de la l�nea de tres cuartos, intentamos encarar
		//  el arco rival.
		if ( pos_balon.getY() > ConstantesMoyatzoBraves.LINEA_TRES_CUARTOS )
		{
			// �ngulo en el que intentar� avanzar el jugador.
			double d_ang = pos_balon.angulo(Constantes.centroArcoSup);

			// Simulamos la acci�n de avanzar con bal�n.
			boolean b_no_interceptan = SimulaAvanceConBalon(d_ang);
			
			// Si no interceptan, podemos avanzar.
			if ( b_no_interceptan )
				a_golpeo_balon.AvanzarConBalon(d_ang);
			else 
			{
				// Vamos a re-intentarlo pero con otro �ngulo.
				if ( pos_balon.getX() > 0 )
					d_ang = Math.PI;
				else
					d_ang = 0.0;

				// Simulamos la acci�n de avanzar con bal�n.
				b_no_interceptan = SimulaAvanceConBalon(d_ang);
				
				// Si no interceptan, podemos avanzar.
				if ( b_no_interceptan )
					a_golpeo_balon.AvanzarConBalon(d_ang);
			}
		}
		else
		{
			// �ngulo en el que intentar� avanzar el jugador.
			double d_ang = ( Math.PI / 2 );

			// Simulamos la acci�n de avanzar con bal�n.
			boolean b_no_interceptan = SimulaAvanceConBalon(d_ang);
			
			// Si no interceptan, podemos avanzar.
			if ( b_no_interceptan )
				a_golpeo_balon.AvanzarConBalon(d_ang);
			else 
			{
				// Vamos a re-intentarlo pero con otro �ngulo.
				if ( pos_balon.getX() > 0 )
					d_ang = Math.PI - ( Math.PI / 9 );
				else
					d_ang = ( Math.PI / 9 );

				// Simulamos la acci�n de avanzar con bal�n.
				b_no_interceptan = SimulaAvanceConBalon(d_ang);
				
				// Si no interceptan, podemos avanzar.
				if ( b_no_interceptan )
					a_golpeo_balon.AvanzarConBalon(d_ang);
			}
		}
	}
	
	//-----
	
	// Simula un avance con bal�n y determina si alg�n rival es capaz de
	//  interceptar el bal�n durante el tiempo en que lo ejecutamos.
	boolean SimulaAvanceConBalon( double ad_angulo )
	{
		// Obtenemos la posici�n del bal�n.
		Posicion pos_balon = _situacion_partido_actual.balon();
		
		// Velocidad inicial del bal�n.
		//  NOTA: Todos mis jugadores tienen velocidad m�xima: ( vel = VELOCIDAD_MAX ).
		double d_velocidad = ( Constantes.VELOCIDAD_MAX + 0.2 ),
        	d_vel_balon_X = ( Math.cos(ad_angulo) * d_velocidad ),
        	d_vel_balon_Y = ( Math.sin(ad_angulo) * d_velocidad );
        
        // Iteraciones que faltan para que mi jugador vuelva a poder
        //  golpear el bal�n.
        int i_iteraciones_para_golpear = ( Constantes.ITERACIONES_GOLPEAR_BALON + 1 );
        
        int i_iteracion_actual = 0;
        
        // �Simulamos el movimiento!
        while ( i_iteraciones_para_golpear > 0 )
        {
        	// Movemos el bal�n.
        	pos_balon = pos_balon.moverPosicion(d_vel_balon_X, d_vel_balon_Y);

        	// Disminu�mos la velocidad del bal�n.
        	d_vel_balon_X = d_vel_balon_X * Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
        	d_vel_balon_Y = d_vel_balon_Y * Constantes.FACTOR_DISMINUCION_VEL_BALON_SUELO;
        	
        	// Calculamos si alg�n jugador rival es capaz de interceptar el bal�n.
        	if ( ( i_iteracion_actual > 0 ) &&
        			( PuedenInterceptarElBalon( pos_balon, i_iteracion_actual ) ) )
        		return false;
        	
        	// Falta una iteraci�n menos para golpear el bal�n.
        	i_iteraciones_para_golpear--;
        	i_iteracion_actual++;
        }
        
        // �Todo Ok!
        return true;
	}
	
	//-----
	
	// Determinamos si alg�n jugador rival puede interceptar el bal�n.
	boolean PuedenInterceptarElBalon( Posicion a_pos_balon, int ai_iteracion )
	{
		// Obenemos las posiciones de los jugadores rivales.
		Posicion pos_rivales[] = _situacion_partido_actual.rivales();
		
		// Obtenemos los detalles de cada jugador rival.
		JugadorDetalle[] det_rivales = _situacion_partido_actual.detalleJugadoresRivales();
		
		// Obtenemos todos los jugadores rivales ordenados por cercan�a a la
		//  posici�n te�rica del bal�n dada.
		int i_indices_rivales[] =
			a_pos_balon.indicesMasCercanos(pos_rivales);
		
		Posicion pos;
		double d_dist_cuad;
		int i_num_rivales = i_indices_rivales.length, i_jug_actual;
		double d_dist_recorrida, d_dist_recorrida_al_cuad;
		
		// Distancia m�xima que puede recorrer cualquier jugador con las iteraciones
		//  que han pasado.
		double d_dist_recorrida_max = ( Constantes.VELOCIDAD_MAX * ai_iteracion ),
			d_dist_recorrida_max_al_cuad = Math.pow(d_dist_recorrida_max, 2);
		
		// Para cada jugador rival...
		for ( int i_index = 0; ( i_index < i_num_rivales );  i_index++ )
		{
			// Obtenemos el jugador actual.
			i_jug_actual = i_indices_rivales[i_index];

			// Obtenemos la posici�n del "actual".
			pos = pos_rivales[i_jug_actual];
			
			// Obtenemos la distancia (al cuadrado) del bal�n al jugador "actual".
			d_dist_cuad = Utilidades.DistanciaAlCuadrado(a_pos_balon, pos);
			
			if ( d_dist_cuad >
				( d_dist_recorrida_max_al_cuad + ConstantesMoyatzoBraves.DISTANCIA_CONTROL_BALON_PORTERO_AL_CUAD + ( 2 * d_dist_recorrida_max * Constantes.DISTANCIA_CONTROL_BALON_PORTERO ) ) )
				// Ning�n jugador podr�a llegar jam�s.
				return false;

			// Distancia que puede recorrer el jugador actual en las iteraciones dadas.
			d_dist_recorrida = ai_iteracion *
				( Constantes.VELOCIDAD_MIN + ( det_rivales[i_jug_actual].getVelocidad() * ConstantesMoyatzoBraves.DIF_VELOCIDADES ) );
			
			// Distancia que puede recorrer el jugador al cuadrado.
			d_dist_recorrida_al_cuad = Math.pow(d_dist_recorrida, 2);
			
			// �Puede llegar al bal�n?
			if ( det_rivales[i_jug_actual].esPortero() )
			{
				// �Podr�a interceptar el bal�n si se desplaza hacia �l (siendo portero)?
				if ( d_dist_cuad <= ( d_dist_recorrida_al_cuad + ConstantesMoyatzoBraves.DISTANCIA_CONTROL_BALON_PORTERO_AL_CUAD + ( 2 * d_dist_recorrida * Constantes.DISTANCIA_CONTROL_BALON_PORTERO ) ) )
					return true;
			}
			else
			{
				// �Podr�a interceptar el bal�n si se desplaza hacia �l?
				if ( d_dist_cuad <= ( d_dist_recorrida_al_cuad + ConstantesMoyatzoBraves.DISTANCIA_CONTROL_BALON_AL_CUAD + ( 2 * d_dist_recorrida * Constantes.DISTANCIA_CONTROL_BALON ) ) )
					return true;
			}
		}
		
		// Por defecto, no llegan a interceptar.
		return false;
	}

	//-----
	
	// Despeja el bal�n.
	private void EjecutaDespeje( InstruccionGolpeoBalon a_golpeo_balon, boolean ab_forzado )
	{
		// Obtenemos la posici�n del bal�n.
		Posicion pos_balon = _situacion_partido_actual.balon();
		
		// Obtenemos la coordenada Y del bal�n.
		double d_pos_balon_Y = pos_balon.getY( ); 
		
		if ( ab_forzado )
		{
			// Se han acabado las opciones, despejamos forzosamente.
			if ( d_pos_balon_Y > 0 )
			{
				if ( d_pos_balon_Y > ConstantesMoyatzoBraves.LINEA_TRES_CUARTOS )
				{
					// Obtenemos la coordenada X del bal�n.
					double d_pos_balon_X = pos_balon.getX( );
					
					// Calculamos un factor que utilizaremos para calcular la fuerza del centro.
					double d_factor = ( Math.abs( d_pos_balon_X ) / ( Constantes.ANCHO_CAMPO_JUEGO / 2 ) );
					d_factor = Math.max( 0, d_factor );
					d_factor = Math.min( 1, d_factor );
					
					// Calculamos la fuerza del centro.
					double d_fuerza = 0.2 + ( 0.8 * d_factor ); 
					
					// Determina la posici�n hacia donde va a ir el centro "cerrado".
					if ( Utilidades.DistanciaAlCuadrado(pos_balon, ConstantesMoyatzoBraves.pos_centro_izq_cerrado) <
						 Utilidades.DistanciaAlCuadrado(pos_balon, ConstantesMoyatzoBraves.pos_centro_der_cerrado) )
						a_golpeo_balon.Despeje(ConstantesMoyatzoBraves.pos_centro_der_cerrado, d_fuerza);
					else
						a_golpeo_balon.Despeje(ConstantesMoyatzoBraves.pos_centro_izq_cerrado, d_fuerza);
				}
				else
				{
					// Calculamos el factor de fuerza a aplicar en el despeje.
					double d_factor_inv = ( d_pos_balon_Y / ConstantesMoyatzoBraves.LINEA_TRES_CUARTOS );
					d_factor_inv = Math.max( 0, d_factor_inv );
					d_factor_inv = Math.min( 1, d_factor_inv );
					
					// Calculamos el factor "real".
					double d_factor = ( 1 - d_factor_inv );
					
					// Calculamos la fuerza del centro.
					double d_fuerza = 0.5 + ( 0.5 * d_factor );
					
					// Determina la posici�n hacia donde va a ir el centro.
					if ( Utilidades.DistanciaAlCuadrado(pos_balon, ConstantesMoyatzoBraves.pos_centro_izq) <
						 Utilidades.DistanciaAlCuadrado(pos_balon, ConstantesMoyatzoBraves.pos_centro_der) )
						a_golpeo_balon.Despeje(ConstantesMoyatzoBraves.pos_centro_der, d_fuerza);
					else
						a_golpeo_balon.Despeje(ConstantesMoyatzoBraves.pos_centro_izq, d_fuerza);
				}
			}
			else
			{
				if ( d_pos_balon_Y < ( - ConstantesMoyatzoBraves.LINEA_TRES_CUARTOS ) )
				{
					// Determina la posici�n hacia donde va a ir el despeje.
					if ( Utilidades.DistanciaAlCuadrado(pos_balon, ConstantesMoyatzoBraves.pos_despeje_izq) <
						 Utilidades.DistanciaAlCuadrado(pos_balon, ConstantesMoyatzoBraves.pos_despeje_der) )
						a_golpeo_balon.Despeje(ConstantesMoyatzoBraves.pos_despeje_izq, 1);
					else
						a_golpeo_balon.Despeje(ConstantesMoyatzoBraves.pos_despeje_der, 1);
				}
				else
				{
					// Distancia (al cuadrado) del bal�n al punto del penalty superior.
					double d_dist_penal = Utilidades.DistanciaAlCuadrado(pos_balon, Constantes.penalSup);

					// Distancia (al cuadrado) del bal�n al punto de centro izquierdo.
					double d_dist_centro_izq = Utilidades.DistanciaAlCuadrado(pos_balon, ConstantesMoyatzoBraves.pos_centro_izq);

					// Distancia (al cuadrado) del bal�n al punto de centro derecho.
					double d_dist_centro_der = Utilidades.DistanciaAlCuadrado(pos_balon, ConstantesMoyatzoBraves.pos_centro_der);
					
					if ( ( d_dist_penal < d_dist_centro_izq ) && ( d_dist_penal < d_dist_centro_der ) )
						a_golpeo_balon.Despeje(Constantes.penalSup, 1);
					else if ( ( d_dist_centro_izq < d_dist_penal ) && ( d_dist_centro_izq < d_dist_centro_der ) )
						a_golpeo_balon.Despeje(ConstantesMoyatzoBraves.pos_centro_izq, 1);
					else
						a_golpeo_balon.Despeje(ConstantesMoyatzoBraves.pos_centro_der, 1);
				}

				// Adoptamos una actitud defensiva; damos por perdido el bal�n.
				_posesion_anterior = PosesionDeBalon.RIVAL;
			}
		}
		else if ( d_pos_balon_Y < ConstantesMoyatzoBraves.ZONA_AREA_PROPIA_Y )
		{
			// Determina la posici�n hacia donde va a ir el despeje.
			if ( Utilidades.DistanciaAlCuadrado(pos_balon, ConstantesMoyatzoBraves.pos_despeje_izq) <
				 Utilidades.DistanciaAlCuadrado(pos_balon, ConstantesMoyatzoBraves.pos_despeje_der) )
				a_golpeo_balon.Despeje(ConstantesMoyatzoBraves.pos_despeje_izq, 1);
			else
				a_golpeo_balon.Despeje(ConstantesMoyatzoBraves.pos_despeje_der, 1);
			
			// Adoptamos una actitud defensiva; damos por perdido el bal�n.
			_posesion_anterior = PosesionDeBalon.RIVAL;
		}
	}
	
	//-----
    
    // Da las instrucciones al equipo en caso de NO tener la posesi�n
    //  del bal�n (defendiendo). 
    private void InstruccionesEnDefensa( )
    {
    	// Reposiciona los jugadores en funci�n de donde est� el bal�n.
    	ReposicionaJugadoresDeCampo( ActitudDelEquipo.DEFENSA );
    	
    	// Varios jugadores (los m�s cercanos y/o los que debe cubrir esa zona
        //  del campo) deber�n salir a presionar al contrario o a atacar el bal�n.
    	JugadoresQueDebenPresionar( );

    	// Reposicionamos al portero.
    	ReposicionaPortero( );
    }
    
    //-----
    
    // Da las instrucciones al equipo en caso de que haya un bal�n dividido
    //  (ambos equipos pueden golpearlo).
    private void InstruccionesPosesionDividida( )
    {
    	// Por precauci�n, adoptamos una posici�n defensiva.
    	ReposicionaJugadoresDeCampo( ActitudDelEquipo.DEFENSA );

    	// Presionamos el bal�n, no sabemos para qui�n ser�.
    	JugadoresQueDebenPresionar( );

    	// Reposicionamos al portero.
    	ReposicionaPortero( );
    	
    	// Instrucciones de golpeo de bal�n.
    	InstruccionesGolpeoBalon( );
    }
    
    //-----
    
    // M�todo espec�fico para reposicionar al portero.
    private void ReposicionaPortero( )
    {
    	// Variable que guardar� la posici�n del portero resultante de los
    	//  c�lculos realizados.
    	Posicion pos_portero;
    	
    	// Obtenemos la situaci�n actual del bal�n.
    	Posicion pos_balon = _situacion_partido_actual.balon();
    	
    	// Calculamos la distancia del bal�n al centro de la propia porter�a.
    	double d_dist = pos_balon.distancia(Constantes.centroArcoInf);
    	
    	// Caso especial, la distancia es 0.
    	if ( d_dist == 0 )
    	{
    		// Tratamos un caso especial, distancia = 0.
    		pos_portero = pos_balon;
    	}
    	else 
    	{
	    	// Obtenemos el �ngulo que forman el bal�n y el centro del arco propio.
	    	double d_ang = pos_balon.angulo(Constantes.centroArcoInf);
	
	    	if ( d_dist > ConstantesMoyatzoBraves.DIST_MEDIA_PRESION_PORTERO )
	    	{
	        	// Si estamos en el �rea de m�nima presi�n alejamos al portero
	    		//  en funci�n de la distancia al bal�n.
	    		pos_portero = pos_balon.moverAngulo(
	    			d_ang, ( d_dist * ConstantesMoyatzoBraves.FACTOR_MIN_PRESION_PORTERO ) );
	    	}
	    	else if ( d_dist > ConstantesMoyatzoBraves.DIST_MAX_PRESION_PORTERO )
	    	{
	        	// Si estamos en el �rea de presi�n media...
	    		
	    		// Calculamos el factor (0..1) de distancia.
	    		double d_factor_dist =
	    			( ( d_dist - ConstantesMoyatzoBraves.DIST_MAX_PRESION_PORTERO ) / ConstantesMoyatzoBraves.DIF_DIST_PRESION_PORTERO_MEDIA_MAX );
	    		
	    		// Calculamos el valor de la distancia respecto al bal�n.
	    		double d_dist_portero =
	    			( d_dist * ( ConstantesMoyatzoBraves.FACTOR_MED_PRESION_PORTERO + ( d_factor_dist * ConstantesMoyatzoBraves.DIF_FACTORES_MIN_MED ) ) );
	
	    		// Establecemos la posici�n del portero.
	    		pos_portero = pos_balon.moverAngulo( d_ang, d_dist_portero );
	    	}
	    	else
	    	{
	    		// Si estamos en el �rea de m�xima presi�n...
	
	    		// Calculamos el factor (0..1) de distancia.
	    		double d_factor_dist =
	    			( d_dist / ConstantesMoyatzoBraves.DIST_MAX_PRESION_PORTERO );
	    		
	    		// Calculamos el valor de la distancia respecto al bal�n.
	    		double d_dist_portero = ( d_factor_dist * ConstantesMoyatzoBraves.DIST_PRESION_PORTERO );
	
	    		// Establecemos la posici�n del portero.
	    		pos_portero = pos_balon.moverAngulo( d_ang, d_dist_portero );
	    	}
    	}
    	
    	// Finalmente, a�adimos la instrucci�n para mover al portero
    	//  (jugador n�m. 0).
		_lista_de_comandos.add(new ComandoIrA(0, pos_portero));
    }
    
    //-----
    
	// Varios jugadores (los m�s cercanos y/o los que debe cubrir esa zona
    //  del campo) deber�n salir a presionar al contrario o a atacar el bal�n.
    private void JugadoresQueDebenPresionar( )
    {
    	// Obtenemos la posici�n del bal�n.
    	Posicion pos_balon = _situacion_partido_actual.balon();
    	
    	// Obtenemos el �ngulo que hay entre el bal�n y el arco propio.
    	double d_ang_arco = pos_balon.angulo(Constantes.centroArcoInf);
    	
    	// Calcula la posici�n donde ubicaremos un jugador para tener siempre
    	//  la porter�a cubierta.
    	Posicion pos_cubre_arco = pos_balon.moverAngulo(d_ang_arco, ConstantesMoyatzoBraves.DIST_PRESION_JUG_CAMPO);
    	
    	// Obtenemos un array ordenado por distancia al bal�n de los jugadores
    	//  (utilizamos las posiciones te�ricas porque el marcaje es zonal).
    	int mas_cercanos[] = pos_balon.indicesMasCercanos(_posiciones_teoricas);
    	
    	// Inicializaciones.
    	Posicion pos_aux;
    	double d_ang_aux, d_dist_cuad, d_dist_pos_cubre_arco = Double.MAX_VALUE;
    	int i_indice_jug, i_indice_real_jug, i_indice_jug_cubre_arco = -1,
    		num_cercanos = Math.min(ConstantesMoyatzoBraves.NUM_JUG_PRESIONAN, mas_cercanos.length);
 	
    	for ( int j = 0; ( j < num_cercanos ); j++ )
    	{
    		// Obtenemos el �ndice del jugador.
    		i_indice_jug = mas_cercanos[j];
    		
    		// Le sumamos 1 porque en el array de posiciones te�ricas no estaba
    		//  el portero.
    		i_indice_real_jug = i_indice_jug + 1;
    		
    		// Distancia (al cuadrado) respecto de la posici�n que cubre el arco propio.
    		d_dist_cuad =
    			Utilidades.DistanciaAlCuadrado( pos_cubre_arco, _posiciones_teoricas[ i_indice_jug ] );

    		// Si est� m�s cerca, ser� el candidato a cubrirla.
    		if ( d_dist_cuad < d_dist_pos_cubre_arco )
    		{
    			d_dist_pos_cubre_arco = d_dist_cuad;
    			i_indice_jug_cubre_arco = i_indice_real_jug;
    		}
    		
    		// Calculamos el �ngulo entre la posici�n del bal�n y la posici�n te�rica
    		//  del jugador.
    		d_ang_aux = pos_balon.angulo( _posiciones_teoricas[ i_indice_jug ] );
    		
    		// Calculamos la posici�n donde el jugador estar para presionar.
    		pos_aux = pos_balon.moverAngulo(d_ang_aux, ConstantesMoyatzoBraves.DIST_PRESION_JUG_CAMPO);

    		// A�adimos la instrucci�n.
    		_lista_de_comandos.add(new ComandoIrA(i_indice_real_jug, pos_aux));
    	}
    	
    	// Seguro que hemos encontrado a alguien que cubra el arco, pero por
    	//  si acaso uso un 'if'.
    	if ( i_indice_jug_cubre_arco != -1 )
    	{
    		// A�adimos la instrucci�n.
    		_lista_de_comandos.add(new ComandoIrA(i_indice_jug_cubre_arco, pos_cubre_arco));
    		
    		// Posici�n actual de mis jugadores.
    		Posicion[] pos_mis_jugs = _situacion_partido_actual.misJugadores();

    		// Obtenemos el �ndice del jugador que realmente est� m�s cerca
    		//  de la posici�n que cubre el arco (exceptuando al portero y al
    		//  jugador que ya hemos elegido antes).
    		int i_indice_mas_cercano_real = pos_cubre_arco.indiceMasCercano(pos_mis_jugs, 0, i_indice_jug_cubre_arco);
    		
    		// Obtenemos la distancia del jugador que realmente est� m�s cerca
    		//  de la posici�n de cubrir el arco.
    		double d_dist_real_mas_cercano =
    			pos_cubre_arco.distancia(pos_mis_jugs[i_indice_mas_cercano_real]);
    		
    		// Obtenemos la distancia del jugador que deber�a presionar esa
    		//  en esa posici�n.
    		double d_dist_jug_cubre_arco =
    			pos_cubre_arco.distancia(pos_mis_jugs[i_indice_jug_cubre_arco]);

    		// Si un jugador est� muy cerca y el que deber�a presionar est�
    		//  bastante m�s alejado...
    		if ( ( d_dist_real_mas_cercano < d_dist_jug_cubre_arco ) &&
    			 ( d_dist_jug_cubre_arco > Constantes.DISTANCIA_CONTROL_BALON ) )
        		// ...a�adimos la instrucci�n para que presione tambi�n el cercano.
        		_lista_de_comandos.add(new ComandoIrA(i_indice_mas_cercano_real, pos_cubre_arco));
    		
    		// Si el rival no puede cambiar la trayectoria del bal�n, comprobamos
    		//  si el bal�n se le acerca a alguno de mis jugadores. 
    		if ( !PuedenRematar( ) )
    		{
    			// Predice la posici�n "futura" del bal�n.
    			Posicion pos_balon_futura = Utilidades.PredicePosBalon(_pos_balon_it_anterior, pos_balon, _situacion_partido_actual.alturaBalon());

    			// Obtenemos los �ndices de los jugadores propios ordenados por
    			//  proximidad al bal�n.
    			int i_inds_jugs_propios[] =
    				pos_balon.indicesMasCercanos(pos_mis_jugs, 0, i_indice_jug_cubre_arco);
    			
    			double d_dist1, d_dist2;
    			int i_jug_actual,
    				i_num_intentos = Math.min( ConstantesMoyatzoBraves.NUM_JUGS_SE_APROXIMA_BALON, i_inds_jugs_propios.length);
    			
    			for ( int i_index = 0; ( i_index < i_num_intentos ); i_index++ )
    			{
    				// Obtenemos el jugador actual.
    				i_jug_actual = i_inds_jugs_propios[i_index];
    				
    				// Obtenemos las distancias respecto a las posiciones actual y futura del bal�n.
    				d_dist1 = Utilidades.DistanciaAlCuadrado(pos_mis_jugs[i_jug_actual], pos_balon);
    				d_dist2 = Utilidades.DistanciaAlCuadrado(pos_mis_jugs[i_jug_actual], pos_balon_futura);

    				if ( d_dist2 < d_dist1 )
    				{
    					// El bal�n se acerca al jugador. �Que el jugador se acerque al bal�n!
    					_lista_de_comandos.add(new ComandoIrA(i_jug_actual, pos_balon_futura));
    					
    					// S�lo lo haremos con uno de los jugadores posibles.
    					i_index = i_num_intentos;
    				}
    			}
    		}    		
    	}
    }
    
    //-----

    // Reposiciona los jugadores de campo en funci�n de donde est� el bal�n y
    //  la "actitud" del equipo (ofensiva o defensiva).
    private void ReposicionaJugadoresDeCampo( ActitudDelEquipo a_actitud )
    {
    	// Consultamos la posici�n actual del bal�n.
    	Posicion pos_balon = _situacion_partido_actual.balon();

    	// Consultamos la coordenada Y para el movimiento 'vertical' del equipo.
    	double d_pos_Y_balon = pos_balon.getY();
    	
    	// "Normalizamos" el valor; debe estar entre 0 y Constantes.LARGO_CAMPO_JUEGO. 
    	d_pos_Y_balon += ( Constantes.LARGO_CAMPO_JUEGO / 2);
    	if ( d_pos_Y_balon < 0 )
    		d_pos_Y_balon = 0;
    	if ( d_pos_Y_balon > Constantes.LARGO_CAMPO_JUEGO )
    		d_pos_Y_balon = Constantes.LARGO_CAMPO_JUEGO;
    	
    	// Calculamos el factor a aplicar sobre cada t�ctica (defensiva o atacante)
    	//  para determinar cu�n adelantado estar� el equipo.
    	double d_factor_adelantado = ( d_pos_Y_balon / Constantes.LARGO_CAMPO_JUEGO );
    	double d_factor_atrasado = 1 - d_factor_adelantado;

    	// Utilizamos las t�cticas de ataque o defensa en funci�n de la actitud
    	//  del equipo en este momento.
    	Posicion pos_adelantada[], pos_atrasada[], posicion_auxiliar;
    	
    	if ( a_actitud == ActitudDelEquipo.ATAQUE )
    	{
    		pos_adelantada = adelantada_en_ataque;
    		pos_atrasada = atrasada_en_ataque;
    	}
    	else
    	{
    		pos_adelantada = adelantada_en_defensa;
    		pos_atrasada = atrasada_en_defensa;
    	}
    	
    	// Ahora tratamos la componente lateral (para bascular a los lados).
    	double d_pos_X_balon = pos_balon.getX();
    	
    	// "Normalizamos" el valor; debe estar dentro del campo. 
    	if ( d_pos_X_balon > ( Constantes.ANCHO_CAMPO_JUEGO / 2 ) )
    		d_pos_X_balon = Constantes.ANCHO_CAMPO_JUEGO / 2;
    	if ( d_pos_X_balon < - ( Constantes.ANCHO_CAMPO_JUEGO / 2 ) )
    		d_pos_X_balon = - Constantes.ANCHO_CAMPO_JUEGO / 2;

    	// Array que copiar� 'bascular_a_derecha' o 'bascular_a_izquierda'
    	//  en funci�n de la posici�n del bal�n.
    	double valores_basculacion[];
    	
    	if ( d_pos_X_balon > 0 )
        	// Si el bal�n est� a la derecha...
    		valores_basculacion = bascular_a_derecha;
    	else
    		// ...o est� a la izquierda.
    		valores_basculacion = bascular_a_izquierda;
    	
    	// Calculamos el factor a aplicar a la basculaci�n.
    	double d_factor_basculacion =
    		Math.abs( d_pos_X_balon ) / ( Constantes.ANCHO_CAMPO_JUEGO / 2 );

    	// Por fin, reposicionamos los jugadores.
    	// �Ojo!: del 1 al 11 porque el portero est� exclu�do aqu�.
        for (int i = 1; i < 11; i++) {
        	posicion_auxiliar = new Posicion(
        			( d_factor_adelantado * pos_adelantada[i].getX() ) + ( d_factor_atrasado * pos_atrasada[i].getX() ) + ( d_factor_basculacion * valores_basculacion[i] ),
        			( d_factor_adelantado * pos_adelantada[i].getY() ) + ( d_factor_atrasado * pos_atrasada[i].getY() ) );
        	
        	// Almacenamos las posiciones te�ricas de esta iteraci�n
        	//  (son necesarias en otros c�lculos posteriores).
        	_posiciones_teoricas[ i - 1 ] = posicion_auxiliar;
        	
        	// Guardamos el ComandoIrA de reposicionamiento.
            _lista_de_comandos.add(new ComandoIrA(i, posicion_auxiliar));
        }
    }
    
    //-----

    public List<Comando> ejecutar(SituacionPartido sp) {
    	
    	// En primer lugar, vaciamos la (antigua) lista de comandos.
    	_lista_de_comandos.clear();

     	// Guardamos la situaci�n del partido (para no tener que pasarla como
    	//  par�metro a los m�todos auxiliares).
    	_situacion_partido_actual = sp;

    	// Determinamos qui�n tiene la posesi�n del bal�n.
    	PosesionDeBalon posesion_actual = DeterminaPosesionDeBalon( );
    	
    	if ( posesion_actual == PosesionDeBalon.RIVAL )
    		// El rival tiene la posesi�n, debemos defender.
    		InstruccionesEnDefensa( );
    	else if ( posesion_actual == PosesionDeBalon.PROPIA )
    		// Tenemos la posesi�n; �ataquemos!
    		InstruccionesEnAtaque( );
    	else
    		// Posesi�n dividida.
    		InstruccionesPosesionDividida( );
    	
    	// Nos guardamos el valor de la posesi�n en esta (�ltima) iteraci�n.
    	_posesion_anterior = posesion_actual;
    	
    	// Nos guardamos la posici�n del bal�n actual para utilizarla en
    	//  la iteraci�n siguiente.
    	_pos_balon_it_anterior = _situacion_partido_actual.balon();
    	
    	return _lista_de_comandos;
    }
}